#include <compilation/instruction/Expression.h>


namespace compilation
{


void
FunctionCallExpression::print(
    std::ostream& out,
    std::function<void(void)> const& indent) const
{
  if (m_function)
    out << m_function->getName() << '(';
  else
    out << "no-function";

  std::vector<VirtualExpression*>::const_iterator iter = m_arguments.begin();
  bool goOn = (iter != m_arguments.end());

  while (goOn)
  {
    (*iter)->print(out, indent);
    if ((goOn = (++iter != m_arguments.end())) != false)
      out << ", ";
  }
  out << ')';
}


void BinaryOperatorExpression::print(
    std::ostream &out,
    const std::function<void ()> &indent) const
{
  out << '(';

  if (m_fst.get())
    m_fst->print(out, indent);
  else
    out << "no-expr";

  out << ' ';

  if (m_operator != OUndefined)
  {
    out << ((m_operator == OPlus)
            ? '+'
            : ((m_operator == OMinus)
               ? '-'
               : ((m_operator == OTimes)
                  ? '*'
                  : '/')));
  }
  else out << "no-op";

  out << ' ';

  if (m_snd.get()) m_snd->print(out, indent);
  else out << "no-expr";

  out << ')';
}


void UnaryOperatorExpression::print(
    std::ostream &out,
    const std::function<void ()> &indent) const
{
  if (m_operator == OUndefined)
    out << "no-op";
  else
    out << ((m_operator == ONeg) ? '!' : '-');

  if (m_subExpression.get())
    m_subExpression->print(out, indent);
  else
    out << "no-expr";
}


void ComparisonExpression::print(
    std::ostream &out,
    const std::function<void ()> &indent) const
{
  out << '(';

  if (m_fst.get())
    m_fst->print(out, indent);
  else
    out << "no-expr";
  out << ' ';

  if (m_operator != OUndefined)
  {
    /**/ if (m_operator <  OCompareEqual    ) out << '<';
    else if (m_operator >  OCompareDifferent) out << '>';
    else if (m_operator == OCompareEqual    ) out << '=';
    else if (m_operator == OCompareDifferent) out << '!';

    if ((m_operator > OCompareLess) && (m_operator < OCompareGreater)) out << '=';
  }
  else out << "no-op";

  out << ' ';

  if (m_snd.get()) m_snd->print(out, indent);
  else out << "no-expr";

  out << ')';
}


void DereferenceExpression::print(
    std::ostream &out,
    const std::function<void ()> &indent) const
{
  out << '*';

  if (m_subExpression.get()) m_subExpression->print(out, indent);
  else out << "no-expr";
}


void ReferenceExpression::print(
    std::ostream &out,
    const std::function<void ()> &indent) const
{
  out << '&';

  if (m_subExpression.get()) m_subExpression->print(out, indent);
  else out << "no-expr";
}


void CastExpression::print(
    std::ostream &out,
    const std::function<void ()> &indent) const
{
  out << '(';

  if (m_type.get()) m_type->print(out);
  else out << "no-type";

  out << ')' << ' ';

  if (m_subExpression.get()) m_subExpression->print(out, indent);
  else out << "no-expr";
}


void AssignExpression::print(
    std::ostream &out,
    const std::function<void ()> &indent) const
{
  if (m_lvalue.get()) m_lvalue->print(out, indent);
  else out << "no-expr";

  out << " = ";

  if (m_rvalue.get()) m_rvalue->print(out, indent);
  else out << "no-expr";
}


void PhiExpression::print(
    std::ostream &out,
    std::function<void()> const& indent) const
{
  out << "phi(" ;
  if (m_fst.get())
  {
    m_fst->print(out, indent);
    if (m_fstFrom)
      out << ' ' << m_fstFrom->getRegistrationIndex();
  }
  else
    out << "no-expr";

  out << ", ";

  if (m_snd.get())
  {
    m_snd->print(out, indent);
    if (m_sndFrom)
      out << ' ' << m_sndFrom->getRegistrationIndex();
  }
  else
    out << "no-expr";
  out << ')';
}


} // compilation
